#include "WriteTestPEFile.h"
#include <stdio.h>

#define FILE_SIZE (sizeof(IMAGE_DOS_HEADER) + 4 + sizeof(IMAGE_FILE_HEADER) + \
	             sizeof(IMAGE_OPTIONAL_HEADER32) + sizeof(IMAGE_SECTION_HEADER) + 3)

#define CODE_SIZE sizeof(code)

void WriteTestPEFile(const TCHAR* filePath)
{
	unsigned int buff[0x1000];
	FILE* file;
	unsigned int bytesToWrite;

	static const BYTE code [0x200] =
	{
		0xB8, 0xFF, 0xFF, 0xFF, 0xFF, // MOV EAX, 0xFFFFFFFF
		0x40, // INC EAX
		0x83, 0xf8, 0xff, // CMP EAX, -1
		0x75, 0xfa, 0x90, // JNE -2
		0xc3 // RET
	};

	//static const BYTE code [] =
	//{
	//	0xB8, 0xFF, 0xFF, 0xFF, 0xFF, // MOV EAX, 0xFFFFFFFF
	//
	//	0x00496CD0, // call
	//	0xEA, 0x9F, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x55, 0x00 // jmp
	//};

	// The only two fields that matter are e_magic and e_lfanew
	static const IMAGE_DOS_HEADER dosHdr =
	{
		IMAGE_DOS_SIGNATURE, // Magic number
		0, // Bytes on last page of file
		0, // Pages in file
		0, // Relocations
		0, // Size of header in paragraphs
		0, // Minimum extra paragraphs needed
		0, // Maximum extra paragraphs needed
		0, // Initial (relative) SS value
		0, // Initial SP value
		0, // Checksum
		0, // Initial IP value
		0, // Initial (relative) CS value
		0, // File address of relocation table
		0, // Overlay number
		{0, 0, 0, 0}, // Reserved words
		0, // OEM identifier (for e_oeminfo)
		0, // OEM information; e_oemid specific
		{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Reserved words
		sizeof(IMAGE_DOS_HEADER) // File address of new exe header
	};

	// IMAGE_NT_SIGNATURE
	static const char peSig [4] = {'P', 'E', '\0', '\0'};

	static const IMAGE_FILE_HEADER imgFileHdr = 
	{
		IMAGE_FILE_MACHINE_I386, // Machine
		1, // NumberOfSections
		1273878786, // TimeDateStamp
		0, // PointerToSymbolTable
		0, // NumberOfSymbols
		sizeof(IMAGE_OPTIONAL_HEADER32), // SizeOfOptionalHeader
		IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_32BIT_MACHINE // Characteristics
	};
	
	static const IMAGE_OPTIONAL_HEADER32 imgOptHdr =
	{
		0x010B, // Magic
		8, // MajorLinkerVersion
		0, // MinorLinkerVersion
		sizeof(code), // SizeOfCode
		0, // SizeOfInitializedData
		0, // SizeOfUninitializedData
		0x1000, //sizeof(IMAGE_DOS_HEADER) + 4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER32) + sizeof(IMAGE_SECTION_HEADER), // AddressOfEntryPoint
		0x1000, //sizeof(IMAGE_DOS_HEADER) + 4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER32) + sizeof(IMAGE_SECTION_HEADER), // BaseOfCode
		FILE_SIZE, // BaseOfData
		0x400000, // ImageBase
		0x1000, // SectionAlignment
		0x200, // FileAlignment
		5, // MajorOperatingSystemVersion
		0, // MinorOperatingSystemVersion
		0, // MajorImageVersion
		0, // MinorImageVersion
		4, // MajorSubsystemVersion
		0, // MinorSubsystemVersion
		0, // Win32VersionValue
		0x1000*2, // SizeOfImage
		sizeof(IMAGE_DOS_HEADER) + 4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER32) + sizeof(IMAGE_SECTION_HEADER), // SizeOfHeaders
		0, // CheckSum
		IMAGE_SUBSYSTEM_WINDOWS_CUI, // Subsystem
		33088, // DllCharacteristics
		0x100000, // SizeOfStackReserve
		0x1000, // SizeOfStackCommit
		0x100000, // SizeOfHeapReserve
		0x1000, // SizeOfHeapCommit
		0, // LoaderFlags
		16, // NumberOfRvaAndSizes
		0 // DataDirectory
	};
	
	static const IMAGE_SECTION_HEADER textSectHdr = 
	{
		{'.', 't', 'e', 'x', 't', 0}, // Name
		CODE_SIZE, // VirtualSize
		0x1000, //sizeof(IMAGE_DOS_HEADER) + 4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER32) + sizeof(IMAGE_SECTION_HEADER), // VirtualAddress
		CODE_SIZE,// SizeOfRawData
		0x200, // sizeof(IMAGE_DOS_HEADER) + 4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER32) + sizeof(IMAGE_SECTION_HEADER), // PointerToRawData
		0, // PointerToRelocations
		0, // PointerToLinenumbers
		0, // NumberOfRelocations
		0, // NumberOfLinenumbers
		0x60000020 // Characteristics
	};

	// Open file
#ifndef UNICODE
	fopen_s(&file, filePath, "wb");
#else
	_wfopen_s(&file, filePath, L"wb");
#endif

	if (!file)
		return;

	fwrite(&dosHdr, sizeof(IMAGE_DOS_HEADER), 1, file);
	fwrite(peSig, sizeof(char), 4, file);
	fwrite(&imgFileHdr, sizeof(IMAGE_FILE_HEADER), 1, file);
	fwrite(&imgOptHdr, sizeof(IMAGE_OPTIONAL_HEADER32), 1, file);
	fwrite(&textSectHdr, sizeof(IMAGE_SECTION_HEADER), 1, file);

	bytesToWrite = 0x200 - ftell(file);
	fwrite(buff, 1, bytesToWrite, file);
	fwrite(code, CODE_SIZE, 1, file);


	fclose(file);
}